package com.fine.hair.manage.controller;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fine.hair.comm.dto.LoginDto;
import com.fine.hair.comm.utils.ApiResponse;
import com.fine.hair.comm.utils.Consts;
import com.fine.hair.comm.utils.MyStatus;
import com.fine.hair.comm.vo.rbac.LoginSuccVo;
import com.fine.hair.comm.vo.rbac.PermissionInfoVo;
import com.fine.hair.manage.config.LoginService;
import com.fine.hair.manage.config.RedisUtils;
import com.fine.hair.manage.config.security.UserPrincipal;
import com.fine.hair.manage.mapper.*;
import com.fine.hair.manage.util.JwtUtil;
import com.fine.hair.comm.model.SecRole;
import com.fine.hair.comm.model.SecRolePermission;
import com.fine.hair.comm.model.SecUser;
import com.fine.hair.comm.model.SecUserRole;
import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import com.fine.hair.comm.exception.SecurityException;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>认证相关接口</p>
 *
 * @author mouseyCat
 * @date 2020/10/22 14:52
 */
@Slf4j
@Api(tags = {"后台登陆相关接口"})
@RestController
@RequestMapping("/auth/")
public class AuthController {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Resource
    private SecUserMapper secUserMapper;
    @Resource
    private SecRoleMapper secRoleMapper;

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private LoginService loginService;

    @Autowired
    private SecUserRoleMapper secUserRoleMapper;

    @Autowired
    private SecRolePermissionMapper secRolePermissionMapper;

    @Resource
    private SecPermissionMapper secPermissionMapper;

    @Autowired
    private RedisUtils redisUtils;
    /**
     * 登录
     */
    @ApiOperation("登陆接口")
    @PostMapping("/login")
    public ApiResponse<LoginSuccVo> login(@Valid @RequestBody LoginDto dto) {
        Authentication authentication;
        try {
            authentication =
                    authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(dto.getUsernameOrPhone(), dto.getPassword()));
        } catch (Exception e) {
            e.printStackTrace();
            log.info("解析账户信息失败，错误信息： {}", e);
          return ApiResponse.ofStatus(MyStatus.USERNAME_PASSWORD_ERROR);
        }

        SecurityContextHolder.getContext()
                .setAuthentication(authentication);

        UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal();

        String jwt = redisUtils.getString(Consts.REDIS_JWT_KEY_PREFIX + userPrincipal.getUsername());
        if (StrUtil.isBlank(jwt)) {
            jwt = jwtUtil.createJWT(authentication, dto.getRememberMe());
        }
        // 构造登陆成功后返回的信息
        return loginService.buildLoginSuccInfo(jwt, dto.getUsernameOrPhone());
    }

    @ApiOperation("获取用户角色名称")
    @GetMapping("user-role-name")
    public ApiResponse userRoleName(HttpServletRequest request) {
        String usernameFromJWT = jwtUtil.getUsernameFromJWT(jwtUtil.getJwtFromRequest(request));
        SecUser secUser = secUserMapper.selectOne(new LambdaQueryWrapper<SecUser>().eq(SecUser::getUsername,
                usernameFromJWT));
        SecUserRole secUserRole =
                secUserRoleMapper.selectOne(new LambdaQueryWrapper<SecUserRole>().eq(SecUserRole::getUserId,
                        secUser.getId()));
        SecRole secRole = secRoleMapper.selectOne(new LambdaQueryWrapper<SecRole>().eq(SecRole::getId,
                secUserRole.getRoleId()));
        return ApiResponse.ofSuccess(secRole.getName());
    }

    @ApiOperation("获取当前用户拥有的权限")
    @PostMapping("/permission")
    public ApiResponse<List<PermissionInfoVo>> permission(HttpServletRequest request) {
        String usernameFromJWT = jwtUtil.getUsernameFromJWT(jwtUtil.getJwtFromRequest(request));
        SecUser secUser = secUserMapper.selectOne(new LambdaQueryWrapper<SecUser>().eq(SecUser::getUsername,
                usernameFromJWT));
        SecUserRole secUserRole =
                secUserRoleMapper.selectOne(new LambdaQueryWrapper<SecUserRole>().eq(SecUserRole::getUserId,
                        secUser.getId()));
        // 根据角色 获取 所有权限id
        List<SecRolePermission> secRolePermissions =
                secRolePermissionMapper.selectList(new LambdaQueryWrapper<SecRolePermission>().eq(SecRolePermission::getRoleId, secUserRole.getRoleId()));
        List<Long> permissionIds =
                secRolePermissions.stream().map(SecRolePermission::getPermissionId).collect(Collectors.toList());
        ArrayList<PermissionInfoVo> permissionInfos = Lists.newArrayList();
        // 查询所有权限信息

        for (Long permissionId : permissionIds) {
            List<PermissionInfoVo> list = secPermissionMapper.selectByPermissionIds(permissionId);
            List<PermissionInfoVo> vo = listToTree(list);
            permissionInfos.addAll(vo);
        }

        // 判断是否存在子类
        for (PermissionInfoVo permissionInfoVo : permissionInfos) {
            List<PermissionInfoVo> child = permissionInfoVo.getChild();
            if (child != null) {
                Iterator<PermissionInfoVo> iterator = child.iterator();
                while (iterator.hasNext()) {
                    {
                        PermissionInfoVo next = iterator.next();
                        Long pId = secRolePermissionMapper.selectByPermissionId(next.getId(),secUserRole.getRoleId());
                        if (pId == null) {
                            iterator.remove();
                        }
                    }
                }
            }
            permissionInfoVo.setChild(child);
        }


        return ApiResponse.ofSuccess(permissionInfos);
    }

    private List<PermissionInfoVo> listToTree(List<PermissionInfoVo> list) {
        ArrayList<PermissionInfoVo> voList = Lists.newArrayList();
        for (PermissionInfoVo tree : list) {
            if (tree.getParentId() == 0L) {
                voList.add(findChild(tree, list));
            }
        }
        return voList;
    }

    private PermissionInfoVo findChild(PermissionInfoVo tree, List<PermissionInfoVo> list) {
        for (PermissionInfoVo node : list) {
            if (node.getParentId().longValue() == tree.getId().longValue()) {
                if (tree.getChild() == null) {
                    tree.setChild(new ArrayList<>());
                }
                tree.getChild().add(findChild(node, list));
            }
        }
        return tree;
    }

    @ApiOperation("登出接口")
    @PostMapping("/logout")
    public ApiResponse logout(HttpServletRequest request) {
        try {
            // 设置JWT过期
            jwtUtil.invalidateJWT(request);
        } catch (SecurityException e) {
            throw new SecurityException(MyStatus.UNAUTHORIZED);
        }
        return ApiResponse.ofStatus(MyStatus.LOGOUT);
    }
}
